package edu.buaa.resourceManager.server;

import edu.buaa.resourceManager.ProgramCMD;
import edu.buaa.resourceManager.controller.*;
import edu.buaa.resourceManager.helper.Utils;

import edu.buaa.resourceManager.vo.FileEntity;
import org.slf4j.Logger;
import spark.*;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;

import static spark.Spark.*;

/**
 * Created by sjh on 17-5-30.
 */
public class SparkHttpServer extends Thread
{
    private static Logger log = Utils.getDevLogger();
    private static Properties config = new Properties();

    public SparkHttpServer(){
        this.setName("Spark HTTP Server starter");
        this.setDaemon(true);
    }


    @Override
    public void run() {

        initExceptionHandler((e) -> log.error("http server start failed.", e));

        exception(Exception.class, (e, req, res) -> {
            log.error("[ERROR] "+req.url(), e);
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            res.type("text/plain");
            res.body(sw.toString());
        }); // print all exceptions

        port(8888);

//        staticFiles.location("/html");
//        staticFiles.externalLocation("/media/song/G680/songjh/projects/resource-manager/src/main/resources/html");
        staticFiles.externalLocation("/media/sjh/data/project/untitled/src/main/resources/html");
        staticFiles.expireTime(1); // ten minutes

        enableCORS("*", "*", "*");

        before("*",(request, response) -> {
            response.type("text/html");
        });

        before("/json/*", (request, response) -> {
            response.type("application/json");
        });

        before("/post/*", (request, response) -> {
            response.type("text/plain");
        });

        get("/", (request, response) -> {
            response.redirect("/search");
            return "";
        });

        // user interface urls
        get("/login",                  UserController.Login);


        get("/browse/path/*",      PathController.Page);
        get("/import",                 ImportController.Page);
        get("/import/path/:path",      ImportController.Page);
        get("/search",                 SearchController.Page);
        get("/search/text/:text",      SearchController.Page);

        get("/shutdown",               shutdown);

        // ajax urls
        get("/json/browse/sha512/:sha512", FileEntityController.SameFiles);
        get("/json/import/:path/info", ImportController.FileInfo);
        get("/json/import/:path/hash", ImportController.FileHash);
        post("/post/import/upload",    ImportController.UploadFile);
        post("/post/import/new",       PathController.NewPathWithEntity);

        get("/json/search/latest",     SearchController.Latest);
        get("/json/search/:text",      SearchController.StringSearch);

//        post("/json/path/update", updateFile);

        after("*",  replaceGlobalConstant);
    }

    private static Route shutdown = (request, response) -> {
        ProgramCMD.exit = true;
        return "shutting down in 1 seconds";
    };

    // Enables CORS on requests. This method is an initialization method and should be called once.
    private static void enableCORS(final String origin, final String methods, final String headers) {

        options("/*", (request, response) -> {

            String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
            if (accessControlRequestHeaders != null) {
                response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
            }

            String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
            if (accessControlRequestMethod != null) {
                response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
            }

            return "OK";
        });

        before((request, response) -> {
            response.header("Access-Control-Allow-Origin", origin);
            response.header("Access-Control-Request-Method", methods);
            response.header("Access-Control-Allow-Headers", headers);
        });
    }

    public static void stopServer() {
        Spark.stop();
    }

    private static Filter replaceGlobalConstant = (request, response) -> {
        if(response.type()!=null && response.type().toLowerCase().equals("text/html")){
            String body = response.body();
            for(String key : config.stringPropertyNames()){
                body = body.replace(key, config.getProperty(key));
            }
            response.body(body);
        }
    };

}
